package net.towee.client.gadgets.recentdocs;

import java.util.Arrays;
import java.util.List;

import net.towee.client.com.app.AppController.Component;
import net.towee.client.com.repo.RepositoryExplorer;
import net.towee.client.com.repo.RepositoryShower;
import net.towee.client.event.core.DocumentReceivedEvent;
import net.towee.client.event.core.DocumentReceivedHandler;
import net.towee.client.event.core.ShowComponentEvent;
import net.towee.client.gadgets.GadgetPresenter;
import net.towee.client.managers.DashBoardManager;
import net.towee.client.managers.DocumentsManager;
import net.towee.model.repo.DocumentData;
import net.towee.model.repo.DocumentType;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasOpenHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.inject.Inject;

public class RecentDocumentsGadget extends GadgetPresenter implements ChangeHandler, ClickHandler,
		OpenHandler<DocumentData> {
	public interface Display extends GadgetPresenter.Display {
		HasChangeHandlers getSearchInputBox();

		String getSearchString();

		HasClickHandlers getMoreResultButton();

		HasOpenHandlers<DocumentData> getDocumentOpener();

		void clearDocuments();

		void showDocument(DocumentData doc);

		void setNewDocumentsCount(Integer result);
		
		void plusNewDocumentsCount();

		void onLoadingStart();

		void onLoadingEnd();
		
		void noMore();

		void showDocumentAtStart(DocumentData result);
	}

	private final AsyncCallback<List<DocumentData>> documentLoadHandler = new AsyncCallback<List<DocumentData>>() {
		@Override
		public void onFailure(Throwable caught) {
		}

		@Override
		public void onSuccess(List<DocumentData> result) {
			display.onLoadingEnd();

			if (offset == 0)
				display.clearDocuments();
			
			offset += perPage;

			for (DocumentData doc : result) {
				display.showDocument(doc);
			}

			if (!loadedCount) {
				loadedCount = true;
				getRecentDocumentsCount();
			}
			
			if(result.size() != perPage)
				display.noMore();
		}
	};

	// Injected
	private final DocumentsManager docManager;
	private final Display display;
	private final HandlerManager eventBus;
	private final RepositoryShower docShower;
	private final RepositoryExplorer docExplorer;

	private final int perPage = 15;
	private int offset = 0;
	private boolean loadedCount = false;

	@Inject
	public RecentDocumentsGadget(RecentDocumentsGadgetView display, DashBoardManager boardManager,
			DocumentsManager docManager, HandlerManager eventBus, RepositoryShower docShower,
			RepositoryExplorer docExplorer) {
		super(display, boardManager);
		this.display = display;
		this.docManager = docManager;
		this.eventBus = eventBus;
		this.docShower = docShower;
		this.docExplorer = docExplorer;

		// Set handlers
		display.getSearchInputBox().addChangeHandler(this);
		display.getMoreResultButton().addClickHandler(this);
		display.getDocumentOpener().addOpenHandler(this);
		
		bindHandlers();
	}

	private void bindHandlers() {
		eventBus.addHandler(DocumentReceivedEvent.TYPE, new DocumentReceivedHandler() {
			@Override
			public void onDocumentReceived(DocumentData result, boolean local) {
				if( getBoard().getAttachedGroups().contains( result.getIdentity().getGroup() )
						&& result.getIdentity().getDocumentTypes().hasDocumentType( DocumentType.SIMPLE_DOC )) {
					display.plusNewDocumentsCount();
					display.showDocumentAtStart(result);
					offset++;
				}
			}
		});
	}

	@Override
	protected void showGadget(HasWidgets container) {
		// Show gadget
		container.add(display.asWidget());

		// Get newest documents
		getDocuments();
	}

	private void getDocuments() {
		display.onLoadingStart();
		docManager.getDocuments(getAttachedGroups(), Arrays.asList(DocumentType.SIMPLE_DOC), offset,
				perPage, documentLoadHandler);
	}

	private void findDocuments(String str) {
		display.onLoadingStart();
		docManager.findDocuments(str, getAttachedGroups(), null, Arrays.asList(DocumentType.SIMPLE_DOC),
				offset, perPage, documentLoadHandler);
	}

	private void getRecentDocumentsCount() {
		// Get number of new documents
		docManager.getRecentDocumentsCount(getAttachedGroups(), Arrays.asList(DocumentType.SIMPLE_DOC),
				new AsyncCallback<Integer>() {
					@Override
					public void onFailure(Throwable caught) {
					}

					@Override
					public void onSuccess(Integer result) {
						display.setNewDocumentsCount(result);
					}
				});
	}

	/**
	 * On show more documents
	 */
	@Override
	public void onClick(ClickEvent event) {
		if (display.getSearchString().isEmpty()) {
			getDocuments();
		} else {
			findDocuments(display.getSearchString());
		}
	}

	/**
	 * On new search string
	 */
	@Override
	public void onChange(ChangeEvent event) {
		// Set zero offset
		offset = 0;

		// If empty string show newest documents
		if (display.getSearchString().isEmpty()) {
			getDocuments();
		} else {
			findDocuments(display.getSearchString());
		}
	}

	/**
	 * On open document
	 */
	@Override
	public void onOpen(OpenEvent<DocumentData> event) {
		// Show repository
		eventBus.fireEvent(new ShowComponentEvent( Component.REPO ));
		
		// Show document
		docShower.showTreeNode( event.getTarget().getNode() );
		docExplorer.selectGroup( event.getTarget().getIdentity().getGroup() );
	}
}
